package cz.cvut.fit.web.nakupniSeznam.ws;

import java.util.ArrayList;
import java.util.HashMap;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cz.cvut.fit.web.nakupniSeznam.constants.DBConstants;
import cz.cvut.fit.web.nakupniSeznam.constants.WSConstants;
import cz.cvut.fit.web.nakupniSeznam.dao.UnitDAO;
import cz.cvut.fit.web.nakupniSeznam.data.Unit;
import cz.cvut.fit.web.nakupniSeznam.ws.conv.ErrorConverter;
import cz.cvut.fit.web.nakupniSeznam.ws.conv.InfoConverter;
import cz.cvut.fit.web.nakupniSeznam.ws.conv.UnitConverter;
import cz.cvut.fit.web.nakupniSeznam.ws.conv.UnitsConverter;

@Path("/unit")
public class Units {
	private static final Logger LOG = LoggerFactory.getLogger(Units.class);
	public static final String SAVE_COMPLETE = "unit saving complete";
	public static final String LOG_OK = "ws succesfully called on unit";
	
//	@Context
//	private UriInfo context;
	private String key;
	
	//====================== GET ======================//

	@GET
	@Produces(WSConstants.WS_PRODUCES)
	/**
	 * Returns informations about user's categories
	 * @return
	 */
	public Response getUnits(@Context HttpHeaders hh) {
		Response.ResponseBuilder builder = Response.status(Response.Status.OK);

		// try to find key in header
		key = AuthLibrary.getKey(hh, builder, LOG);
		if (key == null) {
			return builder.build();
		}

		// check key format
		if (AuthLibrary.checkKeyLength(key, builder, LOG) == false) {
			return builder.build();
		}

		// try to find element in DB
		try {
			java.util.List<Unit> units = UnitDAO.getInstance().getByOwner(key);
			UnitsConverter converter = new UnitsConverter(units);

			builder.entity(converter);
		} catch (NullPointerException ex) {
			builder.status(Response.Status.NOT_FOUND);
			builder.entity(new InfoConverter(WSConstants.RESULT_NOT_FOUND));
			LOG.error(WSConstants.RESULT_FAILED,
					ex);
			return builder.build();
		}

		LOG.debug(Units.LOG_OK);
		return builder.build();
	}
	
	//====================== POST ======================//
	
	@POST
	@Produces(WSConstants.WS_PRODUCES)
	@Consumes(WSConstants.WS_CONSUMES)
	/**
	 * Create new list
	 * @return
	 */
	public Response postUnits(@Context HttpHeaders hh,
			UnitsConverter converter) {
		Response.ResponseBuilder builder = Response
				.status(Response.Status.CREATED);

		// try to find key in header
		key = AuthLibrary.getKey(hh, builder, LOG);
		if (key == null) {
			return builder.build();
		}

		// check key format
		if (AuthLibrary.checkKeyLength(key, builder, LOG) == false) {
			return builder.build();
		}

		try {
			java.util.List<UnitConverter> units = converter.getUnits();
			java.util.List<Unit> newUnits = new ArrayList<Unit>();
			HashMap<Long, Long> idMap = new HashMap<Long, Long>();
			Long id;
			for (UnitConverter u : units) {
				Unit unit = u.retrieveRepresentation();
				//setting the unit owner
				unit.setOwner(key);
				
				// check if there is already unit with such name for this owner
				id = checkUnitPOST(unit);
				idMap.put(id, u.getMobileId());
				
				newUnits.add(UnitDAO.getInstance().getById(id));
				LOG.debug(Units.SAVE_COMPLETE);
			}
			converter = new UnitsConverter(newUnits);
			for (UnitConverter u : converter.getUnits()) {
				u.setMobileId(idMap.get(u.getId()));
			}
			builder.entity(converter);

		} catch (NullPointerException ex) {
			builder.status(Response.Status.BAD_REQUEST);
			builder.entity(new ErrorConverter(DBConstants.DB_BAD_DATA_FORMAT));
			LOG.error(WSConstants.RESULT_FAILED, ex);
			return builder.build();
		}

		LOG.debug(Units.LOG_OK);
		return builder.build();
	}
	
	//====================== PUT ======================//
	
	@PUT
	@Produces(WSConstants.WS_PRODUCES)
	@Consumes(WSConstants.WS_CONSUMES)
	/**
	 * Create new list
	 * @return
	 */
	public Response putUnits(@Context HttpHeaders hh,
			UnitsConverter converter) {
		Response.ResponseBuilder builder = Response
				.status(Response.Status.CREATED);

		// try to find key in header
		key = AuthLibrary.getKey(hh, builder, LOG);
		if (key == null) {
			return builder.build();
		}

		// check key format
		if (AuthLibrary.checkKeyLength(key, builder, LOG) == false) {
			return builder.build();
		}

		try {
			java.util.List<UnitConverter> units = converter.getUnits();
			for (UnitConverter u : units) {
				Unit unit = u.retrieveRepresentation();
				//setting the unit owner
				unit.setOwner(key);
				UnitDAO.getInstance().save(unit);
				LOG.debug(Units.SAVE_COMPLETE);
			}
			builder.entity(new InfoConverter(Units.SAVE_COMPLETE));

		} catch (NullPointerException ex) {
			builder.status(Response.Status.BAD_REQUEST);
			builder.entity(new ErrorConverter(DBConstants.DB_BAD_DATA_FORMAT));
			LOG.error(WSConstants.RESULT_FAILED, ex);
			return builder.build();
		}

		LOG.debug(Units.LOG_OK);
		return builder.build();
	}
	//====================== DELETE ======================//

	//====================== OTHER =======================//
	
	/**
	 * Checks if there is already unit with such name for this user in DB
	 * 
	 * @param unit 
	 * @return id of unit in DB
	 */
	public Long checkUnitPOST(Unit unt) {
		Unit unit = UnitDAO.getInstance().getByOwnerAndName(unt.getOwner(), unt.getName());
		if(unit == null) {
			return UnitDAO.getInstance().save(unt);
		}
		else {
			return unit.getId();
		}
	}
}
